package com.admin.util.cacheUtil;

import com.admin.config.redis.MyRedisUtil;
import com.fegin.bean.admin.AdminUser;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.*;

/**
 * @author 张子艺
 * @packge com.util.cache
 * @data 2019-01-10 13:45
 * @project Currency
 */
@Component
public class JedisUtil {
    private final Logger logger = LoggerFactory.getLogger(JedisUtil.class);

    @Autowired
    MyRedisUtil redisManager;


    @Value("${shiro.redis.session}")
    String shiro_redis_session = "";

    @Value("${shiro.redis.cache}")
    String shiro_redis_cache = "";

    /**
     * 设置 list
     *
     * @param <T>
     * @param key
     */
    public <T> void setList(String key, List<T> list,Integer time) {
        try {
            redisManager.set(key.getBytes(), ObjectTranscoder.serialize(list),time);
        } catch (Exception e) {
            e.printStackTrace(System.out);
            logger.error("设置List类型缓存时出错");

        }
    }

    /**
     * 获取list
     *
     * @param <T>
     * @param key
     * @return list
     */
    public <T> List<T> getList(String key) {
        byte[] in = redisManager.get(key.getBytes());
        List<T> list = (List<T>) ObjectTranscoder.deserialize(in);
        return list;
    }


    /**
     * 设置 map
     *
     * @param <T>
     * @param key
     */
    public <T> void setMap(String key, Map<String, T> map,Integer time) {
        try {
            redisManager.set(key.getBytes(), ObjectTranscoder.serialize(map));
        } catch (Exception e) {
            e.printStackTrace(System.out);
            logger.error("设置Map类型缓存时出错");
        }
    }

    /**
     * 获取Map
     *
     * @param <T>
     * @param key
     * @return list
     */
    public <T> Map<String, T> getMap(String key) {

        byte[] in = redisManager.get(key.getBytes());
        Map<String, T> map = (Map<String, T>) ObjectTranscoder.deserialize(in);
        return map;
    }

    /**
     * 设置 过期时间
     *
     * @param key
     * @param value   新值
     */
    public void setString(String key,  String value,Integer time) {
        try {
            value = value==null||value.equals("") ? "" : value;
            redisManager.set(key.getBytes(), value.getBytes(), time);
        } catch (Exception e) {
            logger.error("设置" + key + "的缓存时间时候出错 ");
            e.printStackTrace(System.out);
        }
    }

    /**
     * 获取String值
     *
     * @param key
     * @return value
     */
    public String getString(String key) {
        return new String(redisManager.get(ObjectTranscoder.serialize(key)));
    }

    /**
     * 设置String值
     *
     * @param key
     * @return value
     */
    public String setString(String key, String value) {
        return new String(redisManager.set(key.getBytes(), value.getBytes()));
    }

    /**
     * 删除一个key
     */
    public void del(String key) {
        redisManager.del(key.getBytes());
    }

    /**
     * 模糊删除
     */
    public void delByParam(String keyParam) {
        Set<byte[]> strings = redisManager.keys(keyParam);
        for (byte[] key : strings) {
            redisManager.del(key);
        }

    }

    /**
     * 删除某个用户的session缓存以及 该用户信息的缓存
     *
     */
    public void delSessionCache(String userName) {
        String cacheName=shiro_redis_cache+userName;
        //移除本个账户的缓存信息
        redisManager.del( cacheName.getBytes());
        //获取redis 中 所有用户session  键
        Set<byte[]> bytes = redisManager.keys(shiro_redis_session + "*");
        //循环字节
        for (byte[] key : bytes) {
            //获取该键的用户session字节
            byte[] sessionCache = redisManager.get(key);
            //把字节转成session
            Session session = (Session) ByteToObject(sessionCache);
            //强转为shiro对象
            SimplePrincipalCollection simplePrincipalCollection=(SimplePrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            Collection<AdminUser> users=simplePrincipalCollection.byType(AdminUser.class);
            for (AdminUser u:users){
                //如果本次用户信息账户是当前传入的参数账户 就移除他的session缓存
                 if(u.getUsername().equals(userName)){
                     redisManager.del( key);
                 }
            }
        }
        //移除本个线程中的subject 否则会出现 当前会话的session已被干掉 但是旧的session接着执行后续方法 造成报错
        //同时也中断本个账户的未来操作
        ThreadContext.remove(ThreadContext.SUBJECT_KEY);
    }
    /**
     * 获取当前所有shiro存在redis  session中  未失效的用户 在线用户信息
     *
     */
    public  List<AdminUser> getAllSession( ) {
        List<AdminUser> list=new ArrayList<>();
        //获取redis 中 所有用户session  键
        Set<byte[]> bytes = redisManager.keys(shiro_redis_session + "*");
        //循环字节
        for (byte[] key : bytes) {
            //获取该键的用户session字节
            byte[] sessionCache = redisManager.get(key);
            //把字节转成session
            Session session = (Session) ByteToObject(sessionCache);
            //强转为shiro对象
            SimplePrincipalCollection simplePrincipalCollection=(SimplePrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            Collection<AdminUser> users=simplePrincipalCollection.byType(AdminUser.class);
            for (AdminUser u:users){
                list.add(u);
            }
        }
        return  list;
    }

    /**
     * 更新一个key
     */
    public void update(String key, Object value,Integer time) {
        redisManager.del(key.getBytes());
        if (value instanceof List) {
            setList(key, (List<? extends Object>) value,time);
        }
        if (value instanceof Map) {
            setMap(key, (Map<String, ? extends Object>) value,time);
        }
        if (value instanceof String) {
            setString(key, (String) value,time);
        }
    }


    /**
     * byte转对象
     *
     * @param bytes
     * @return
     */
    private Object ByteToObject(byte[] bytes) {
        Object obj = null;
        try {
            // bytearray to object
            ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
            ObjectInputStream oi = new ObjectInputStream(bi);

            obj = oi.readObject();
            bi.close();
            oi.close();
        } catch (Exception e) {
            logger.error("字节转对象出错：" + e.getMessage());
            e.printStackTrace();
        }
        return obj;
    }
}
